/*
 * Copyright (C) 2007-2012 by XDEV Software, All Rights Reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License version 3.0 as published by the Free Software Foundation.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
 
package xdev.ui;


import java.awt.Component;
import java.awt.Container;
import java.util.List;
import java.util.Map;

import javax.swing.JComponent;

import xdev.db.Operator;
import xdev.db.sql.Column;
import xdev.db.sql.Condition;
import xdev.lang.NotNull;
import xdev.util.CollectionUtils;
import xdev.vt.VirtualTable;
import xdev.vt.VirtualTableColumn;
import xdev.vt.VirtualTables;


class FormularUtils implements ClientProperties
{
	static String getName(Component component, boolean dataBound)
	{
		if(component instanceof FormularComponent)
		{
			String dataField = ((FormularComponent)component).getDataField();
			if(dataField != null && dataField.length() > 0)
			{
				return dataField;
			}
		}
		
		if(dataBound)
		{
			return null;
		}
		
		return component.getName();
	}
	
	
	static Object getValue(@NotNull Component component)
	{
		if(component instanceof FormularComponent)
		{
			return ((FormularComponent)component).getFormularValue();
		}
		
		if(component instanceof JComponent)
		{
			Object tagData = ((JComponent)component).getClientProperty(TAG_DATA);
			if(tagData != null)
			{
				return tagData;
			}
		}
		
		return null;
	}
	
	
	static VirtualTable getConnectedVT(FormularComponent fc)
	{
		String dataField = fc.getDataField();
		if(dataField != null && dataField.length() > 0)
		{
			int si = dataField.lastIndexOf('.');
			if(si > 0)
			{
				dataField = dataField.substring(0,si);
			}
			
			return VirtualTables.getVirtualTable(dataField);
		}
		
		return null;
	}
	
	
	static VirtualTableColumn getVirtualTableColumn(String dataField)
	{
		if(dataField != null && dataField.length() > 0)
		{
			int si = dataField.lastIndexOf('.');
			if(si > 0)
			{
				String table = dataField.substring(0,si);
				VirtualTable vt = VirtualTables.getVirtualTable(table);
				if(vt != null)
				{
					String column = dataField.substring(si + 1);
					return vt.getColumn(column);
				}
			}
		}
		
		return null;
	}
	
	
	static void collectFormularValues(Container parent,
			final Map<String, List<FormularValue>> formularValues, final boolean withNulls)
	{
		ComponentTreeVisitor visitor = new ComponentTreeVisitor()
		{
			public Object visit(Component cpn)
			{
				if(cpn instanceof FormularComponent && !((FormularComponent)cpn).isReadOnly())
				{
					String name = getName(cpn,true);
					if(name != null)
					{
						Object value = getValue(cpn);
						if((withNulls || !isNull(value)))
						{
							CollectionUtils.accumulate(formularValues,name,new FormularValue(
									(FormularComponent)cpn,value));
						}
					}
				}
				
				return null;
			}
		};
		
		if(parent instanceof XdevFormular)
		{
			((XdevFormular)parent).lookupComponentTree(visitor);
		}
		else
		{
			UIUtils.lookupComponentTree(parent,visitor);
		}
	}
	
	
	static void addData(Container parent, final Map<String, Object> formularValues,
			final boolean withNulls)
	{
		ComponentTreeVisitor visitor = new ComponentTreeVisitor()
		{
			public Object visit(Component cpn)
			{
				if(cpn instanceof FormularComponent && !((FormularComponent)cpn).isReadOnly())
				{
					String name = getName(cpn,true);
					if(name != null)
					{
						Object value = getValue(cpn);
						if((withNulls || !isNull(value)))
						{
							formularValues.put(name,value);
						}
					}
				}
				
				return null;
			}
		};
		
		if(parent instanceof XdevFormular)
		{
			((XdevFormular)parent).lookupComponentTree(visitor);
		}
		else
		{
			UIUtils.lookupComponentTree(parent,visitor);
		}
	}
	
	
	private static boolean isNull(Object value)
	{
		if(value == null)
		{
			return true;
		}
		
		if(value instanceof String && ((String)value).length() == 0)
		{
			return true;
		}
		
		return false;
	}
	
	
	
	static interface ParameterContainer
	{
		void addParameters(Object... params);
	}
	
	
	static Condition createWhereCondition(String connector, ParameterContainer paramContainer,
			Map<String, List<FormularValue>> formularValues)
	{
		if(!("AND".equalsIgnoreCase(connector) || "OR".equalsIgnoreCase(connector)))
		{
			throw new IllegalArgumentException("illegal connector: " + connector);
		}
		
		Condition where = null;
		
		for(String key : formularValues.keySet())
		{
			for(FormularValue formularValue : formularValues.get(key))
			{
				Column column = getVirtualTableColumn(key);
				if(column == null)
				{
					column = new Column(key);
				}
				
				Condition condition = null;
				Operator operator = formularValue.formularComponent.getFilterOperator();
				
				boolean useDefault = true;
				if(formularValue.formularComponent.isMultiSelect()
						&& (operator == Operator.IN || operator == Operator.NOT_IN))
				{
					useDefault = false;
					if(formularValue.value != null && formularValue.value.getClass().isArray())
					{
						Object[] values = (Object[])formularValue.value;
						paramContainer.addParameters(values);
						
						Object[] params = new String[values.length];
						for(int i = 0; i < params.length; i++)
						{
							params[i] = "?";
						}
						
						if(operator == Operator.IN)
						{
							condition = column.IN(params);
						}
						else
						{
							condition = column.NOT_IN(params);
						}
					}
				}
				
				if(useDefault)
				{
					Object value = formularValue.value;
					
					switch(operator)
					{
						case NOT_LIKE_$:
						case LIKE_$:
						{
							value = value + "%";
						}
						break;
						
						case NOT_LIKE$_:
						case LIKE$_:
						{
							value = "%" + value;
						}
						break;
						
						case NOT_LIKE$_$:
						case LIKE$_$:
						{
							value = "%" + value + "%";
						}
						break;
					}
					
					if(paramContainer != null)
					{
						paramContainer.addParameters(value);
						value = "?";
					}
					
					switch(operator)
					{
						case EQUAL:
						{
							condition = column.eq(value);
						}
						break;
						
						case NOT_EQUAL:
						{
							condition = column.ne(value);
						}
						break;
						
						case SMALLER:
						{
							condition = column.lt(value);
						}
						break;
						
						case SMALLER_EQUAL:
						{
							condition = column.lte(value);
						}
						break;
						
						case GREATER:
						{
							condition = column.gt(value);
						}
						break;
						
						case GREATER_EQUAL:
						{
							condition = column.gte(value);
						}
						break;
						
						case LIKE:
						case LIKE_$:
						case LIKE$_:
						case LIKE$_$:
						{
							condition = column.LIKE(value);
						}
						break;
						
						case NOT_LIKE:
						case NOT_LIKE_$:
						case NOT_LIKE$_:
						case NOT_LIKE$_$:
						{
							condition = column.LIKE(value);
						}
						break;
						
						case IN:
						{
							condition = column.IN(value);
						}
						break;
						
						case NOT_IN:
						{
							condition = column.NOT_IN(value);
						}
						break;
					}
				}
				
				if(condition != null)
				{
					if(where == null)
					{
						where = condition;
					}
					else if("AND".equalsIgnoreCase(connector))
					{
						where = where.AND(condition);
					}
					else if("OR".equalsIgnoreCase(connector))
					{
						where = where.OR(condition);
					}
				}
			}
		}
		
		return where;
	}
	
	
	static void validateFormularComponents(Container parent, final Validation validation)
	{
		UIUtils.lookupComponentTree(parent,new ComponentTreeVisitor()
		{
			public Object visit(Component cpn)
			{
				if(cpn instanceof FormularComponent)
				{
					try
					{
						((FormularComponent)cpn).validateState(validation);
					}
					catch(ValidationException e)
					{
						// cancel
						return e;
					}
				}
				
				return null;
			}
		});
	}
	
	
	
	static class FormularValue
	{
		private FormularComponent	formularComponent;
		private Object				value;
		
		
		private FormularValue(FormularComponent formularComponent, Object value)
		{
			this.formularComponent = formularComponent;
			this.value = value;
		}
	}
}
